/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_ssap_client_hdi.h"
#include "sle_ssap_config.h"
#include "sle_ssap_client_config.h"
#include "sle_hal_errcode.h"
#include "sle_hilog.h"
#include "sle_ssap_client.h"
#include "sle_callback_adapter.h"
#include <time.h>
#ifndef SLE_CONNECT_DEFAULT_INTERVAL
#define SLE_CONNECT_DEFAULT_INTERVAL 16
#endif //SLE_CONNECT_DEFAULT_INTERVAL

extern uint32_t g_hasSendPack;
extern uint32_t NEED_GIVE_DOG_FOOD;
extern uint32_t SEND_TIMES_FOR_DOG;
SleHdiErrorCode SleHdiAdapterSsapcRegisterClient(const SleUuid *appUuid, uint8_t *clientId)
{
    SLE_ASSERT_AND_RETURN_RET(appUuid != NULL, SLE_HDI_ERRCODE_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(clientId != NULL, SLE_HDI_ERRCODE_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssapc_register_client((sle_uuid_t*) appUuid, clientId);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapcUnregisterClient(uint8_t clientId)
{
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssapc_unregister_client(clientId);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapcFindStructure(uint8_t clientId, uint16_t connectId, const ClientFindStructure *param)
{
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_HDI_ERRCODE_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ssapc_find_structure_param_t param_sdk = {
        .type = (uint8_t)param->findType,
        .start_hdl = param->startHandle,
        .end_hdl = param->endHandle,
        .reserve = param->reserve,
    };
    memcpy(&(param_sdk.uuid), &(param->uuid), sizeof(sle_uuid_t));
    ret = ssapc_find_structure(clientId, connectId, &param_sdk);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapcReadReqByUuid(uint8_t clientId, uint16_t connectId, const ClientReadReqByUUID *param)
{
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_HDI_ERRCODE_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ssapc_read_req_by_uuid_param_t param_sdk = {
        .type = (uint8_t)param->findType,
        .start_hdl = param->startHandle,
        .end_hdl = param->endHandle,
    };
    memcpy(&(param_sdk.uuid), &(param->uuid), sizeof(sle_uuid_t));
    ret = ssapc_read_req_by_uuid(clientId, connectId, &param_sdk);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapcReadReq(uint8_t clientId, uint16_t connectId, uint16_t handle, uint8_t type)
{
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssapc_read_req(clientId, connectId, handle, type);
    return ret;
}

// 例如SLE_CONNECT_DEFAULT_INTERVAL = 16, 连接间隔
// 该接口严格在1个连接间隔只能发送一个包(修复上面接口的BUG, 一定要等待连接间隔的整数倍), 丢包率1%以内, 单包时延2ms,即1个连接间隔
static SleHdiErrorCode sle_write_sync(uint8_t clientId, uint16_t connectId, ssapc_write_param_t *param, bool isReq)
{
    SleHdiErrorCode ret = -1;
    uint8_t data_num = gle_tx_acb_data_num_get();   //获取当前缓冲区大小
    uint32_t watchDog = 0;
    while (data_num == 0) {
        watchDog++;
        if (watchDog % 100 == 0) {
            (void)uapi_watchdog_kick();
        }
        if (watchDog > SEND_TIMES_FOR_DOG) {
            watchDog = 1;
        }
        LOS_TaskYield();
        data_num = gle_tx_acb_data_num_get();
    }
    if(isReq) {
        ret = ssapc_write_req(clientId, connectId, param);
    } else {
        ret = ssapc_write_cmd(clientId, connectId, param);
    }
    if (ret == 0){
        g_hasSendPack++;
        if (g_hasSendPack >= NEED_GIVE_DOG_FOOD) {
            (void)uapi_watchdog_kick();
            g_hasSendPack = 0;
        }
    }
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_HDI_ERRCODE_SUCC, ret);
    // SLE_LOGD("brew call sle_write_sync ret=0x%08X, seq:%d, data_num=%d\n", (uint32_t)ret, param->data[0], data_num);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapcWriteReq(uint8_t clientId, uint16_t connectId, const ClientWriteParam *param)
{
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_HDI_ERRCODE_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ssapc_write_param_t param_sdk = {
        .handle = param->handle,
        .type = (uint8_t)param->type,
        .data_len =param-> dataLength,
        .data = param->data,
    };
    ret = sle_write_sync(clientId, connectId, &param_sdk, true);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapcWriteCmd(uint8_t clientId, uint16_t connectId, const ClientWriteParam *param)
{
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_HDI_ERRCODE_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ssapc_write_param_t param_sdk = {
        .handle = param->handle,
        .type = (uint8_t)param->type,
        .data_len =param-> dataLength,
        .data = param->data,
    };
    ret = sle_write_sync(clientId, connectId, &param_sdk, false);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapcExchangeInfoReq(uint8_t clientId, uint16_t connectId, const SsapMtuInfo* param)
{
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_HDI_ERRCODE_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssapc_exchange_info_req(clientId, connectId, (ssap_exchange_info_t*)param);
    return ret;
}

SleHdiErrorCode SleHdiAdapterRegisterSsapcCallbacks(SleSsapcHdiCallbacks *ssapcCallbacks)
{
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = RegisterSsapcCallbackAdapter(ssapcCallbacks);
    return ret;
}

SleHdiErrorCode GetSleSsapcHdiOpts(SleSsapcHdiOpts *ssapcOpts)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(ssapcOpts != NULL, SLE_HAL_ERR_INVALID_PARAM, "GetSleSsapcHdiOpts");
    ssapcOpts->registerClient = SleHdiAdapterSsapcRegisterClient;
    ssapcOpts->unregisterClient = SleHdiAdapterSsapcUnregisterClient;
    ssapcOpts->findStructure = SleHdiAdapterSsapcFindStructure;
    ssapcOpts->readReqByUuid = SleHdiAdapterSsapcReadReqByUuid;
    ssapcOpts->readReq = SleHdiAdapterSsapcReadReq;
    ssapcOpts->writeReq = SleHdiAdapterSsapcWriteReq;
    ssapcOpts->writeCmd = SleHdiAdapterSsapcWriteCmd;
    ssapcOpts->exchangeInfoReq = SleHdiAdapterSsapcExchangeInfoReq;
    ssapcOpts->registerClientCbks = SleHdiAdapterRegisterSsapcCallbacks;
    return SLE_HDI_ERRCODE_SUCC;
}